package xworker.swt.data;

import ognl.Ognl;
import ognl.OgnlException;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.xmeta.ActionContext;
import org.xmeta.Thing;
import xworker.swt.app.view.swt.widgets.form.DataObjectForm;
import xworker.dataObject.data.DataBinderManager;
import xworker.dataObject.DataObject;
import xworker.dataObject.DataObjectList;
import xworker.dataObject.DataObjectListListener;
import xworker.dataObject.DataStore;
import xworker.swt.dataObject.SwtDataStore;
import xworker.swt.dataObject.bind.BindItemFactory;
import xworker.swt.dataObject.bind.BinderItem;
import xworker.swt.dataObject.bind.DataObjectBinder;
import xworker.lang.executor.Executor;
import xworker.swt.design.Designer;
import xworker.swt.reacts.DataReactors;
import xworker.swt.xworker.ThingForm;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DataManager {
	private static final String TAG = DataManager.class.getName();
	private static final String KEY = "__DataManager_CACHED_DATA__";

	static{
		DataBinderManager.registDataBinder((source, target, params, actionContext) -> {
			if(source instanceof DataStore){
				DataStore dataStore = (DataStore) source;
				return SwtDataStore.bind(dataStore, target, params, actionContext) != null;
			}else if(source instanceof DataObjectList){
				if(target instanceof DataObjectListListener){
					((DataObjectList) source).addListener((DataObjectListListener) target);
					return true;
				}

				DataStore dataStore = new DataStore((DataObjectList) source, actionContext);
				return SwtDataStore.bind(dataStore, target, params, actionContext) != null;
			}else if(source instanceof DataObject){
				DataObject data = (DataObject) source;
				if(target instanceof Thing){
					Thing thing = (Thing) target;
					if(ThingForm.getThingForm(thing) != null){
						ThingForm thingForm = ThingForm.getThingForm(thing);
						thingForm.setDescriptor(data.getMetadata().getDescriptor());
						thingForm.setValues(data);
						return true;
					}else if(DataObjectForm.getDataObjectForm(thing) != null){
						DataObjectForm dataObjectForm = DataObjectForm.getDataObjectForm(thing);
						dataObjectForm.setDataObject(data);
						return true;
					}
				}
			}

			return false;
		});
	}
	
	public static void initDataBinds(Map<Object, Object> context, Control control, ActionContext actionContext) throws OgnlException {
		String dataBinds = (String) control.getData("dataBinds");
		if(dataBinds != null) {
			for(String line : dataBinds.split("[\n]")) {
				line = line.trim();
				if(line.startsWith("#") || "".equals(line)) {
					continue;
				}
				
				int index = line.indexOf("|");
				if(index == -1) {
					//无法解析
					Thing thing = Designer.getThing(control);
					Executor.info(TAG, "Can not parse line '" + line + "', no '|'  path=" + (thing != null ? thing.getMetadata().getPath() : "" ));
					continue;
				}
				
				String dataPath = line.substring(0, index).trim();
				String attributeName = line.substring(index + 1).trim();
				
				Object data = Ognl.getValue(dataPath, actionContext);
				if(data instanceof DataObject) {
					DataObject dataObject = (DataObject) data;
						
					DataObjectBinder binder = (DataObjectBinder) context.get(dataObject);
					if(binder == null) {
						binder = new DataObjectBinder(dataObject, control, actionContext);
						context.put(dataObject, binder);
						
						actionContext.g().put(dataPath + "DataObjectBinder", binder);
					}
					
					String valuePath = attributeName;
					index = attributeName.indexOf(":");					
					if(index != -1) {
						valuePath = attributeName.substring(index + 1).trim();
						attributeName = attributeName.substring(0, index).trim();
					}
					
					BinderItem item = BindItemFactory.create(attributeName, valuePath, control, actionContext);
					if(item != null) {
						binder.addBinderItem(item);
					}					
				} else {
					Thing thing = Designer.getThing(control);
					Executor.info(TAG, "Not supported object type, " +
							"" + (data != null ? data.getClass().getSimpleName() : null) + ", path=" + (thing != null ? thing.getMetadata().getPath() : ""));
				}
			}
		}
		
		String reactorRules = (String) control.getData("reactorRules");
		if(reactorRules != null && !"".equals(reactorRules)) {
			DataReactors.createRules(reactorRules, actionContext);
		}
		
		if(control instanceof Composite) {
			for(Control child : ((Composite) control).getChildren()) {
				initDataBinds(context, child, actionContext);
			}
		}
	}
	
	public static void create(ActionContext actionContext) throws OgnlException {
		Thing self = actionContext.getObject("self");
		
		for(Thing child : self.getChilds()) {
			child.doAction("create", actionContext);
		}

		//控件里设置的绑定
		Control parent = actionContext.getObject("parent");
		Map<Object, Object> context = new HashMap<>();
		initDataBinds(context, parent, actionContext);

		//对象之间的绑定，如DataStore绑定表格等等
		String objectBinds = self.doAction("getObjectBinds", actionContext);
		DataBinderManager.bind(actionContext, objectBinds);

		//激活响应器
		List<String> fireLoadReactors = self.doAction("getFireLoadReactors", actionContext);
		DataReactors.fireLoadReactors(fireLoadReactors, actionContext);

		//触发数据对象改变事件，确保首次也能够生效
		for(Object key : context.keySet()){
			Object obj = context.get(key);
			if(obj instanceof DataObjectBinder){
				DataObjectBinder binder = ((DataObjectBinder) obj);
				binder.changed(binder.getDataObject());
			}
		}
	}
}
